package s_processPkg

import (
	"Infinichat_mixed/back/mapper"
	"Infinichat_mixed/entity"
	"Infinichat_mixed/server/s_utils"
	"Infinichat_mixed/transfer"
	"context"
	"encoding/json"
	"fmt"
	"github.com/redis/go-redis/v9"
	//"github.com/garyburd/redigo/redis"
	"github.com/google/uuid"
	"github.com/streadway/amqp"
	"net"
	"time"
)

type SmsProcess struct {
}

func (this *SmsProcess) SendBroadcastMes(mes *entity.Message) {
	var smsMes entity.SmsMes
	err := json.Unmarshal([]byte(mes.Data), &smsMes)
	if err != nil {
		fmt.Println(err)
		return
	}
	data, err := json.Marshal(mes)
	if err != nil {
		fmt.Println(err)
		return
	}
	for id, up := range OnlineUserMgr.OnlineUsers {
		if id == smsMes.User.ID {
			continue
		}
		this.SendMes2OnlineUser(data, up.Conn)
	}
}

func (this *SmsProcess) SendMes2OnlineUser(bodyData []byte, conn net.Conn) {
	tf := &transfer.Transfer{
		Conn: conn,
	}
	err := tf.WriterPkg(bodyData)
	if err != nil {
		fmt.Println("Write err:", err)
		return
	}
}

func GetP2PMsg(sid, tid uint) []entity.P2PMsg {
	// 先在redis中查聊天记录
	if sid > tid {
		// 因为可能是3_1，这样交换可以使得redis只用维护一份数据就可以了
		sid, tid = tid, sid
	}
	zsetKey := entity.GetMsgZsetKey(sid, tid)
	syncField := entity.GetSyncField(sid, tid) // 同步标记
	syncSetKey := entity.GetSyncSetKey(sid, tid)
	//redisConn := s_utils.RedisPool.Get()
	//defer redisConn.Close()
	//isSync, err := redis.String(redisConn.Do("GET", syncField))
	isSync, err := s_utils.RedisClient.Get(context.Background(), syncField).Result()
	var retMsgs []entity.P2PMsg
	if err != nil || isSync != "1" {
		if err != nil {
			fmt.Println("读取redis出现了错误：", err)
		}
		fmt.Println("数据从MySQL中加载...")
		// 出现其他错误（包括键不存在） 或者 没同步过
		// 从mysql加载
		retMsgs, _ = mapper.FindChattingRec(sid, tid)
		// 将消息记录逐条写入redis
		for _, retMsg := range retMsgs {
			msgJson, _ := json.Marshal(retMsg)
			//// 写入消息记录
			//_, _ = redisConn.Do("ZADD", zsetKey, retMsg.SendTime.Unix(), msgJson)
			//// 记录已刷入mysql的数据
			//_, _ = redisConn.Do("SADD", syncSetKey, retMsg.ID)
			_, _ = s_utils.RedisClient.ZAdd(s_utils.Ctx, zsetKey, redis.Z{
				Score:  float64(retMsg.SendTime.Unix()),
				Member: msgJson,
			}).Result()
			_, _ = s_utils.RedisClient.SAdd(s_utils.Ctx, syncSetKey, retMsg.ID).Result()
		}
		// 标记已从Mysql中同步过
		//_, _ = redisConn.Do("SET", syncField, 1)
		_, _ = s_utils.RedisClient.Set(s_utils.Ctx, syncField, 1, 0).Result()
	} else {
		// 同步过，从redis中读取
		fmt.Println("数据从redis中加载...")
		//msgData, _ := redis.Values(redisConn.Do("ZRANGE", zsetKey, "0", "-1"))
		msgData, _ := s_utils.RedisClient.ZRange(s_utils.Ctx, zsetKey, 0, -1).Result()
		for _, md := range msgData {
			var retMsg entity.P2PMsg
			_ = json.Unmarshal([]byte(md), &retMsg)
			retMsgs = append(retMsgs, retMsg)
		}
	}
	return retMsgs
}

func (this *SmsProcess) SendMes2One(mes *entity.Message) {
	var smsMesOne entity.P2PMsg
	err := json.Unmarshal([]byte(mes.Data), &smsMesOne)
	if err != nil {
		return
	}

	// 存储到p2p_msg中
	var p2p_mes = &entity.P2PMsg{
		ReceiveId: smsMesOne.ReceiveId,
		SendId:    smsMesOne.SendId,
		Content:   smsMesOne.Content,
		Type:      1,
		IsRead:    false,
		SendTime:  time.Now(),
		Uuid:      uuid.New().String(),
	}

	// 同步redis-mysql的聊天记录：其实这段没必要，真实的通信场景是先读取聊天记录，然后再同步数据的，但为了健壮性还是做了这一层校验
	sid, tid := smsMesOne.SendId, smsMesOne.ReceiveId
	if sid > tid {
		// 因为可能是3_1，这样交换可以使得redis只用维护一份数据就可以了
		sid, tid = tid, sid
	}
	_ = GetP2PMsg(sid, tid)
	zsetKey := entity.GetMsgZsetKey(sid, tid)
	// 延迟到守护协程去执行数据库写入操作
	//_ = mapper.Save_p2pMes(p2p_mes)
	//redisConn := s_utils.RedisPool.Get()
	//defer redisConn.Close()
	msgJson, _ := json.Marshal(p2p_mes)
	//_, _ = redisConn.Do("ZADD", zsetKey, p2p_mes.SendTime.Unix(), msgJson)
	//// 加入活跃会话集合中，方便守护线程进行扫描
	//_, _ = redisConn.Do("SADD", "active:zsetKeys", zsetKey)
	// 写入有序集合
	ctx := context.Background()
	_, _ = s_utils.RedisClient.ZAdd(ctx, zsetKey, redis.Z{
		Score:  float64(p2p_mes.SendTime.Unix()),
		Member: msgJson,
	}).Result()
	// 加入活跃 zsetKey 集合
	_, _ = s_utils.RedisClient.SAdd(ctx, "active:zsetKeys", zsetKey).Result()
	// 先确定该用户是否在线
	// 如果在线 则直接推送 如果不在线 则等待用户登录了再推送 ==> 改为存入rabbitmq队列
	pro := OnlineUserMgr.OnlineUsers[p2p_mes.ReceiveId]
	if pro != nil {
		mesData, _ := json.Marshal(p2p_mes)
		mes.Data = string(mesData)
		data, err := json.Marshal(mes)
		if err != nil {
			fmt.Println(err)
		}
		this.SendMes2OnlineUser(data, pro.Conn)
	} else {
		// 存入rabbitmq队列
		queueName := fmt.Sprintf("p2p_unread_msg_%d", p2p_mes.ReceiveId) // 发送到对方的未读消息队列
		_ = UnreadMsgPublish(queueName, p2p_mes)
	}

	return
}

func UnreadMsgPublish(queue string, unreadMsg *entity.P2PMsg) error {
	ch, _ := s_utils.MQ.Channel()
	defer ch.Close()

	body, _ := json.Marshal(unreadMsg)

	ch.QueueDeclare(
		queue, true, false, false, false, nil)
	return ch.Publish(
		"", queue, false, false,
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})

}

func (this *SmsProcess) SendMes2Group(mes *entity.Message) {
	var smg entity.SmsMes2Group
	err := json.Unmarshal([]byte(mes.Data), &smg)
	if err != nil {
		fmt.Println(err)
	}

	// 先存储到groupMsg中
	gm := &entity.GroupMsg{
		SenderId:   smg.User.ID,
		Content:    smg.Content,
		GroupId:    smg.Gid,
		ReadMember: []uint{smg.User.ID},
		Type:       1,
	}
	err = mapper.SaveGroupMes(gm)
	if err != nil {
		fmt.Println(err)
	}
	userIds, err := mapper.FindUserGMes(smg.User.ID, smg.Gid)
	if err != nil {
		fmt.Println(err)
	}

	data, err := json.Marshal(gm)
	if err != nil {
		fmt.Println(err)
	}
	for _, uid := range userIds {
		// 推送给在线且在该群聊的用户
		pro := OnlineUserMgr.OnlineUsers[uid]
		if pro != nil {
			this.SendMes2OnlineUser(data, pro.Conn)
		}
	}
}
